\chapter{Implementatie}
\label{Implementatie}
Dit hoofdstuk beschrijft de policy taal die gebruikt zal worden, als ook hoe men policies kan afdwingen op een stuk code. 
Verder zullen we nodige aanpassingen uitleggen, die in Narcissus moesten gemaakt worden om dit mogelijk te maken. 
Voor het prototype van JSWebjail zal er enkel een subset van alle gevoelige JavaScript operaties afgeschermd worden aangezien het nog om een proof-of-concept gaat. 
We hebben de operaties die we wel zullen afschermen zo gekozen dat er van elke soort operaties (property, function, Object, etc.) 
er minstens \'e\'en afgeschermd kan worden. De nodige aanpassingen die moesten gemaak worden om het systeem veilig te maken worden in Hoofdstuk \ref{Beveiliging} beschreven.

\section{Policies}
De policies zijn gestructureerd, zoals bij Webjail \cite{webjail}. Ze staan toe om verschillende groepen gevoelige JavaScript operaties
die aan elkaar gerelateerd zijn aan of uit te schakelen. De indeling van de gekozen groepen is te zien in Tabel \ref{tab:policies}.

\begin{table}[position specifier]
\begin{tabular}{l l}
\hline
Groep           & Operaties \\
\hline
domaccess-read  & DOM lees operaties. \\
		& Bv: document.getElementById(), etc. \\
domaccess-write & DOM schrijf operaties. \\
		& Bv: document.write(),  etc. \\
cookies-read    & Cookie lees rechten. \\
cookies-write   & Cookie schrijf rechten. \\
extcomm         & Externe communicatie. \\
		& Bv: XMLHttpRequest, WebSocket, etc. \\
framecomm       & Inter frame communicate. \\
		& Bv: window.postMessage(), window.onmessage. \\
storage-read    & Storage read access. \\
		& Bv: window.localStorage.setItem(), FileAPI, etc.\\
storage-write   & Storage write access. \\
		& Bv: window.localStorage.getItem(), FileAPI, etc. \\
ui              & History API en drag and drop events. \\
media           & Media capture API\\
geolocation     & Geolocation access. \\
		& Bv: navigator.geolocation.getCurrentPosition(), etc. \\
device          & Device access. \\	
\hline
Aantal gevoelige operaties: 86 \\
\hline\end{tabular}
\caption{Indeling gevoelige operaties.}
\label{tab:policies}
\end{table}

Het formaat van de policies is in JavaScipt Object Notation (JSON), dit is een eenvoudig formaat dat makkelijk geparset kan worden.
Elke policy is een whitelist van alle groepen gevoelige operaties die kunen toegestaan worden, elke groep die niet voorkomt in de policy wordt automatisch geblokkeerd, maar deze kunnen ook nog expliciet geweigerd worden.

\begin{lstlisting}[caption=Voorbeeld van een policy.]
 { 'cookie-read' : 'yes',
   'cookie-write' : 'yes',
   'extcomm' : 'yes',
   'geolocation' : 'no' }
\end{lstlisting}

\pagebreak

\subsubsection{Policies toepassen}

Om een policy toe te passen op een stuk code is de Narcissus.interpreter.evaluate() methode zo aangepast dat er een policy aan meegegeven kan worden als argument.
De meegegeven policy zal dan toegepast worden op de ge\"evalueerde code. De policy zal blijven toegepast worden op elk stuk code die ge\"evalueerd wordt
totdat er een nieuwe policy meegegeven wordt.

\medskip
\begin{lstlisting}[caption=Voorbeeld van een policy die meegegeven wordt met een stuk code.]
  Narcissus.interpreter.evauate("alert(document.cookie);", {'cookie-read':'yes'});
\end{lstlisting}

\pagebreak

\section{Aanpassingen aan Narcissus}

Buiten de Narcissus.interpreter.evaluate() functie zijn er nog twee andere functies aangepast en eentje toegevoegd.
De toegevoegde functie is de functie Narcissus.interpreter.parsePolicy() die dan een policy object omzet naar een gegevensstructuur
die dan gebruikt wordt door de aangepaste Narcissus.intepreter.getValue() en Narcissus.interpreter.putValue() functies. Deze aanpassingen zullen
in deze sectie beschreven worden.

\subsection{Narcissus.interpreter.evaluate()}

De originele Narcissus.interpreter.evaluate() methode van Narcissus moest zo aangepast worden dat er een policy zou kunnen meegegeven worden. 
De meegegeven policy zal dan omgezet worden naar een interne gegevensstructuur door de Narcissus.interpreter.parsePolicy() methode op te roepen.

\medskip
\begin{lstlisting}[caption=Originele Narcissus.interpreter.evaluate(). lib/jsexec.js]

 function evaluate(s, f, l) {
    if (typeof s !== "string")
        return s;
    var x = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version);
    var ast = parser.parse(s, f, l);
    if (x.version === "harmony") {
       resolveGlobal(ast);
       nstantiateModules(ast, x.scope);
    }
    x.execute(ast);
    return x.result;
 }
\end{lstlisting}

\pagebreak

\medskip
\begin{lstlisting}[caption=Aagepaste Narcissus.interpreter.evaluate(). lib/jsexec.js]

 var activePolicy; //added
 var JSON_active_policy;//added
 function evaluate(s, p, f, l) {
    if (typeof s !== "string")
        return s;

    if(JSON_active_policy !== p || !activePolicy){ //added
       JSON_active_policy = p; //added
       activePolicy = parsePolicy(p); //added
    }
    var x = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version);
    var ast = parser.parse(s, f, l);
    if (x.version === "harmony") {
       resolveGlobal(ast);
       nstantiateModules(ast, x.scope);
    }
    x.execute(ast);
    return x.result;
 }
\end{lstlisting}

\subsection{Narcissus.interpreter.parsePolicy()}

De methode Narcissus.interpreter.parsePolicy() zet policies om naar een interne gegevensstructuur.
Deze gegevensstructuur is eigenlijk twee hashtabelen, \'e\'en wordt gebruikt bij het lezen van operaties,
de andere bij het schrijven, deze tabelen noemen we read en write.
 
Elke tabel heeft als sleutels de gevoelige operaties die afgeschermd moeten worden. Bij read zijn de waarden van de tabel
de gevoelige operatie, indien die toegestaan is, ofwel een dummy functie of een dummy waarde zodat code die gebruik maakt
van niet toegestane operaties niet zou crashen. Bij write is de waarde 'yes' als deze operatie toegestaan is, anderzijds 'no'.

Listing \ref{lst:parsePolicy} toont een verkorte versie van de Narcissus.interpreter.parsePolicy() methode. De prototype zal, zoals eerder vermeld,
enkel een subset van alle gevoelige operaties kunnen afschermen. Deze subset hebben we zo gekozen dat er wel \'e\'en voorbeeld van alle
soorten operatie is.

De soorten operaties zijn:
\begin{itemize}
  \setlength{\parskip}{0.0in}
  \setlength{\itemindent}{1.0em}
  \item Properties bv: document.cookie.
  \item Functies zonder callback bv: localStorage.setItem(), localStorage.getItem().
  \item Functies met callback bv: navigator.geolocation.watchPosition(), eventlisteners.
  \item Objecten bv: document.XMLHttpRequest, 
  \item DOM bv: document.getElementById(), document.createElement().
\end{itemize}

\medskip
\begin{lstlisting}[caption=Verkorte versie van Narcissus.interpreter.parsePolicy(). lib/jsexec.js, label=lst:parsePolicy] 
 function parsePolicy(p) {
        p = (p == undefined) ? {} : p;
        var ruleSet = {}; 
        
        ruleSet.read = new Object();
        ruleSet.write = new Object();        
        if (p['cookie-read'] === 'yes') {
            ruleSet.read[document]["cookie"] = document.cookie;
        } else {
            ruleSet.read[document]["cookie"] = 'No cookie reads allowed';
        }

        if (p['cookie-write'] == 'yes') {
            ruleSet.write[document]["cookie"] = 'yes';
        } else {
            ruleSet.write[document]["cookie"] = 'no';
        }
        
        if (p['domaccess-read'] === 'yes') {
            ruleSet.read[document]["getElementById"] = document.getElementById;
            ruleSet.write[document]["getElementById"] = 'no';
            //Add all other DOM read operations
        } else {
            ruleSet.read[document]["getElementById"] = function() { return "No DOM read access" };
            ruleSet.write[document]["getElementById"] = 'no';
            //Add all other DOM read operations
        }
        
        return ruleSet;
   }
\end{lstlisting}

Deze methode kan makkelijk uitgebreid worden om meer functies af te schermen. De functie moet gewoon toegevoegd worden aan het gegevensstructuur
bij de juiste check. Listing \ref{lst:parsePolicy2} toont de nodige aanpassingen die moeten gemaakt worden om Listing \ref{lst:parsePolicy} 
de methode document.getElementsByTagName() ook te kunnen afschermen.

\pagebreak

\medskip
\begin{lstlisting}[caption=Verkorte versie van Narcissus.interpreter.parsePolicy(). lib/jsexec.js, label=lst:parsePolicy2] 
 function parsePolicy(p) {
        p = (p == undefined) ? {} : p;
        var ruleSet = {}; 
        
        ruleSet.read = new Object();
        ruleSet.write = new Object();        
        if (p['cookie-read'] === 'yes') {
            ruleSet.read[document]["cookie"] = document.cookie;
        } else {
            ruleSet.read[document]["cookie"] = 'No cookie reads allowed';
        }

        if (p['cookie-write'] == 'yes') {
            ruleSet.write[document]["cookie"] = 'yes';
        } else {
            ruleSet.write[document]["cookie"] = 'no';
        }
        
        if (p['domaccess-read'] === 'yes') {
            ruleSet.read[document]["getElementById"] = document.getElementById;
            ruleSet.write[document]["getElementById"] = 'no';
            ruleSet.read[document]["getElementsByTagName"] = document.getElementsByTagName; //added
            ruleSet.write[document]["getElementsByTagName"] = 'no'; //added
            
            //Add all other DOM read operations
        } else {
            ruleSet.read[document]["getElementById"] = function() { return "No DOM read access" };
            ruleSet.write[document]["getElementById"] = 'no';
            ruleSet.read[document]["getElementsByTagName"] = function() { return "No DOM read access" }; //added
            ruleSet.write[document]["getElementsByTagName"] = 'no'; //added
            //Add all other DOM read operations
        }
        
        return ruleSet;
   }
\end{lstlisting}

\subsection{Narcissus.interpreter.getValue()}

In JavaScript is alles een referentie naar een object, binnenin een JavaScript engine is er dus een functionaliteit die referenties kan
omzetten naar de objecten waarnaar ze wijzen. Deze functionaliteit wordt aangeboden in elke JavaScript engine onder de vorm van de methode getValue(), deze methode wordt verder besproken in de JavaScript specificaties \cite{ecma}.

De referenties zijn in Narcissus ge\"implementeerd als Reference objecten, dit zijn objecten met twee properties: Reference.base en Reference.propertyName.
Reference.base houdt het basisobject bij en Reference.propertyName houdt bij naar welke eigenschap van het basisobject de Reference naar wijst.
Een Reference wijst dus altijd naar een property van een object. Dit is mogelijk omdat in JavaScript objecten altijd properties worden
van het object in welk hun scope ze zijn gecre\"eert, in geval van de global scope worden ze dan properties van het global object. Een referentie naar
het global object kan ook gemaakt worden want \'e\'en van de properties van het global object is het global object zelf.

\medskip
\begin{lstlisting}[caption=Originele Narcissus.interpreter.getValue(). lib/jsexec.js]
 function getValue(v) {
        if (v instanceof Reference) {
            if (!v.base) {
                var e = 'throw new ReferenceError("'+ v.propertyName + ' is not defined, ' +                  				v.node.filename + ', ' + v.node.lineno + '");';
                 Narcissus.interpreter.evaluate(e);
            }
            return v.base[v.propertyName];
        }
        return v;
    }
\end{lstlisting}

De methode Narcissus.intepreter.getValue() is zo aangepast dat deze gebruikt maakt van de eerder aangemaakte gegevensstructuur 
in Narcissus.intepreter.parsePolicy(). Als een gevraagde referentie aanwezig is in de read tabel van de gegevensstructuur,
zal de waarde van deze referentie in de read tabel opgehaald worden en teruggegeven worden. Deze methode werkt om alle paden naar een
bepaald object af te schermen omdat al deze paden referenties zijn naar hetzelfde object. Deze methode vergelijkt de objecten en niet de referenties zelf.

\medskip
\begin{lstlisting}[caption=Aangepaste Narcissus.interpreter.getValue(). lib/jsexec.js]
 function getValue(v) {
    if (v instanceof Reference) {
        if (!v.base) {
            var e = 'throw new ReferenceError("'+ v.propertyName + ' is not defined, ' + v.node.filename + ', ' + v.node.lineno + '");';
            Narcissus.interpreter.evaluate(e);
        }
        if( activePolicy.read[v.base] && activePolicy.read[v.base][v.propertyName] !== undefined) {
            return activePolicy.read[v.base][v.propertyName];
        } else {
            return v.base[v.propertyName];
        }
    }
\end{lstlisting}

\pagebreak

\subsection{Narcissus.interpreter.putValue()}

In JavaScript is niet enkel een functionaliteit nodig die objecten waarnaar referenties wijzen teruggeven maar ook een die
objecten waarnaar referenties wijzen kan overschrijven. Deze functionaliteit wordt aangeboden in elke JavaScript engine onder
de vorm van de methode putValue(), deze methode wordt verder besproken in de JavaScript specificaties \cite{ecma}.

\medskip
\begin{lstlisting}[caption=Originele Narcissus.interpreter.putValue(). lib/jsexec.js]
 function putValue(v, w, vn) {
        if (v instanceof Reference) {
           return (v.base || global)[v.propertyName] = w;
        }
        var e = 'throw new ReferenceError("Invalid assignment left-hand side,'+ vn.filename + ', ' +vn.lineno + '”);';
        Narcissus.interpreter.evaie luate(e);
   }
\end{lstlisting}

De methode Narcissus.intepreter.putValue() is zo aangepast dat deze gebruikt maakt van de eerder aangemaakte gegevensstructuur in Narcissus.intepreter.parsePolicy(). Als een gevraagde referentie aanwezig is in de write tabel van de gegevensstructuur
zal het object waarnaar de referentie wijst enkel en alleen overschreven worden als de waarde in de write tabel 'yes' is. 
Ook hier worden alle paden naar een object volledig afgeschermd.

\medskip
\begin{lstlisting}[caption=Aangepaste Narcissus.interpreter.putValue(). lib/jsexec.js]
 function putValue(v, w, vn) {
     if (v instanceof Reference) {
         if(activePolicy.write[v.base] && activePolicy.write[v.base][v.propertyName] !== undefined) {
             return activePolicy.write[v.base][v.propertyName] === 'yes' ? v.base[v.propertyName] = w : null;
         } else {
             return (v.base || global)[v.propertyName] = w;
         }
     }
     var e = 'throw new ReferenceError("Invalid assignment left-hand side,'+ vn.filename + ', ' +vn.lineno + '”);';
     Narcissus.interpreter.evaluate(e);
 }
\end{lstlisting}
